package mycollections;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

public class MyArrayList<T> implements MyList<T>, RandomAccess {

	int size;
	private static final int DEFAULT_CAPACITY = 10;
	Object[] arr;

	public MyArrayList() {
		arr = new Object[DEFAULT_CAPACITY];
	}
	
	public MyArrayList(MyList<T> c) {
		arr = c.toArray();
		size = arr.length;
	}
	
	public MyArrayList(int initialCapacity) {
		if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
		arr = new Object[initialCapacity];
	}

	public Iterator<T> iterator() {
		return new MyArrayListIterator();
	}

	public int size() {
		return size;
	}

	@Override
	public void add(T e) {
		ensureCapacity();
		arr[size++] = e;
	}

	public void add(int index, T e) {
		rangeCheckForAdd(index);
		ensureCapacity();
		System.arraycopy(arr, index, arr, index + 1, size - index);
		arr[index] = e;
		size++;
	}

	public void addAll(T[] c) {
		ensureCapacityInternal(c.length);
		System.arraycopy(c, 0, arr, size, c.length);
		size += c.length;
	}

	public void addAll(int index, T[] c) {
		rangeCheckForAdd(index);
		ensureCapacityInternal(c.length);
		System.arraycopy(arr, index, arr, index + c.length, size - index);
		System.arraycopy(c, 0, arr, index, c.length);
		size += c.length;
	}

	public T get(int index) {
		rangeCheck(index);
		@SuppressWarnings("unchecked") T el = (T) arr[index];
		return el;
	}

	public T remove(int index) {
		rangeCheck(index);
		@SuppressWarnings("unchecked") T elementToRemove = (T) arr[index];
		size--;
		System.arraycopy(arr, index + 1, arr, index, size - index);
		return elementToRemove;
	}

	public void clear() {
		arr = new Object[DEFAULT_CAPACITY];
		size = 0;
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public void set(int index, T value) {
		rangeCheck(index);
		arr[index] = value;
	}

	public int indexOf(T value) {
		if(value == null) {
			for(int i = 0; i < size; i++)
				if(arr[i] == null)
					return i;
		} else {
		for (int i = 0; i < size; i++)
			if (value.equals(arr[i]))
				return i;
		}
		return -1;
	}

	public Object[] toArray() {
		return Arrays.copyOf(arr, size);
	}
	
	public void ensureCapacity(int minCapacity) {		
		arr = Arrays.copyOf(arr, minCapacity);
	}
	
	public void trimToSize() {
		arr = Arrays.copyOf(arr, size);
	}

	private void ensureCapacity() {
		if (size == arr.length)
			arr = Arrays.copyOf(arr, arr.length * 2);
	}
	
	private void ensureCapacityInternal(int req) {
		if (size + req >= arr.length)
			arr = Arrays.copyOf(arr, (size + req) * 2);
	}
	
	private void rangeCheck(int index) {
        if (index >= size || index < 0)
            throw new MyIndexOutOfBoundsException("Index: "+index+", Size: "+size);
    }
	
	private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new MyIndexOutOfBoundsException("Index: "+index+", Size: "+size);
    }

	private class MyArrayListIterator implements Iterator<T> {

		private int position;
		private int lastRet = -1;

		public boolean hasNext() {
			return position != size;
		}

		public T next() {
			if (position >= size)
				throw new NoSuchElementException();
			return (T) get(lastRet = position++);
		}

		public void remove() {
			if (lastRet == -1)
				throw new IllegalStateException();
			MyArrayList.this.remove(lastRet);
			position = lastRet;
			lastRet = -1;
		}

	}
}
